﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Input;

namespace game
{
    public abstract class Camera
    {
        public Matrix View { get; set; }
        public Matrix Projection { get; set; }

        /// <summary>
        /// View marix properties
        /// </summary>
        public Vector3 Position { get; set; }
        public Vector3 Target { get; set; }
        public Vector3 UpVector { get; set; }
        
        /// <summary>
        /// Projection marix properties
        /// </summary>
        public float AspectRatio { get; set; }
        public float FieldOfView { get; set; }
        public float FarPlaneDistance { get; set; }
        public float NearPlaneDistance { get; set; }

        public BoundingFrustum Frustum
        {
            get
            {
                if (frustumUpToDate == false)
                {
                    frustum.Matrix = View * Projection;
                    frustumUpToDate = true;
                }
                return frustum;
            }
        }
        protected BoundingFrustum frustum = new BoundingFrustum(Matrix.Identity);
        protected bool frustumUpToDate = false;

        /// <summary>
        /// Camera constructor
        /// </summary>
        /// <param name="Position"></param>
        /// <param name="Target"></param>
        /// <param name="UpVector"></param>
        /// <param name="FieldOfView"></param>
        /// <param name="NearPlaneDistance"></param>
        /// <param name="FarPlaneDistance"></param>
        /// <param name="AspectRatio"></param>
        public Camera(Vector3 Position, Vector3 Target, Vector3 UpVector,
            float FieldOfView, float NearPlaneDistance, float FarPlaneDistance, float AspectRatio)
        {
            this.Position = Position;
            //this.Target = Target;
            this.UpVector = UpVector;
            this.FieldOfView = FieldOfView;
            this.NearPlaneDistance = NearPlaneDistance;
            this.FarPlaneDistance = FarPlaneDistance;
            this.AspectRatio = AspectRatio;

            this.Position.Normalize();
            this.Target.Normalize();

            // Create view and projection
            View = Matrix.CreateLookAt(Position, Target, UpVector);
            Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(FieldOfView),
                AspectRatio, NearPlaneDistance, FarPlaneDistance);

            frustum = new BoundingFrustum(View * Projection);
        }

        public virtual void Update(GameTime gameTime)
        {
        }

        /// <summary>
        /// This is where view matrix is updated
        /// </summary>
        protected void UpdateViewMatrix()
        {
            View = Matrix.CreateLookAt(Position, Target, UpVector);
            frustumUpToDate = false;
        }

        public virtual void Shake(float strength) {}
    }
}
